//
//  SSRefreshControl.swift
//  shanshanlol微博
//
//  Created by 叶竞泽 on 2017/1/29.
//  Copyright © 2017年 JingZe. All rights reserved.
//

import UIKit

/// 刷新状态切换的临界点
private let RefreshOffset: CGFloat = 126

/// 刷新状态
///
/// - Normal: 普通,什么都不做
/// - Pulling: 正在拖动
/// - WillRefresh: 超过临界点,并且放手

/// 刷新控件 - 负责刷新相关的逻辑处理
class SSRefreshControl: UIControl {
    
    // MARK: - 属性
    
    /// 滚动视图的父视图,下拉刷新控件应该适用于tableView和collectionView
    fileprivate weak var scrollView: UIScrollView?
    
    fileprivate lazy var refreshView: SSRefreshView? = SSRefreshView.refreshView()
    
    /// 是否刷新标记
    var isRefreshing: Bool?
    
    /// 构造函数
    init() {
        
        super.init(frame: CGRect())
        
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        
        super.init(coder: aDecoder)
        
        setupUI()
    }
    
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        // 记录父视图,判断父视图的类型
        guard let sv = newSuperview as? UIScrollView else {
            return
        }
        
        scrollView = sv
        
        // 监听父视图的contenOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
    }
    
    /// 本视图从父视图上移除
    /// 所有下拉刷新的控件实现思路都是监听父视图的contenSize
    override func removeFromSuperview() {
        
        // 此时父视图还在
        
        // 移除kvo监听
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        
        super.removeFromSuperview()
        
        // 此时父视图不存在
    }
    
    /// 所有kvo方法会统一调用此方法
    /// 在观察者模式中,通常只监听一个对象的某几个属性,如果属性太多,会很乱
    /// kvo观察者模式,在不需要的时候,都要释放
    /// 关于释放
    /// -通知中心:如果不释放,什么也不会发生,但是会有内存泄漏,会有多次注册的可能
    /// -kvo:如果不释放,会崩溃
    ///
    /// - Parameters:
    ///   - keyPath: 监听的属性
    ///   - object: 被监听的对象
    ///   - change: 改变的属性
    ///   - context:
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        guard let sv = scrollView else {
            return
        }
        
        /// 初始高度
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        
        if height < 0 {
            return
        }
        
        // 传递父视图高度 - 如果正在刷新中,不传递
        if refreshView?.refreshState != .WillRefresh {
            refreshView?.parentHeight = height
        }
        
        frame = CGRect(x: 0, y: -height, width: sv.bounds.width, height: height)
        
        // 判断临界点 - 只需要判断一次
        if sv.isDragging {
            // 如果高度大于60并且刷新状态等于normal,状态改为pulling
            if height > RefreshOffset && refreshView?.refreshState == .Normal {
                refreshView?.refreshState = .Pulling
            }
                // 如果高度小于60并且状态等于pulling,状态改为normal
            else if height <= RefreshOffset && refreshView?.refreshState == .Pulling {
                refreshView?.refreshState = .Normal
            }
        } else {
            // 松手后,如果高度大于60并且状态等于pulling,状态改为willrefresh
            if refreshView?.refreshState == .Pulling {

                beginRefreshing()
                sendActions(for: .valueChanged)
            }
        }
    }
    
    /// 开始刷新
    func beginRefreshing() {
        
        // 判断父视图
        guard let sv = scrollView else {
            return
        }
        
        // 如果正在刷新,就退出
        if refreshView?.refreshState == .WillRefresh {
            return
        }
        
        // 设置刷新状态
        refreshView?.refreshState = .WillRefresh
        
        refreshView?.parentHeight += RefreshOffset
        
        // 调整表格间距
        UIView.animate(withDuration: 0.25) {
            sv.contentInset.top += RefreshOffset
        }
        
    }
    
    /// 结束刷新
    func endRefreshing() {
        
        guard let sv = scrollView else {
            return
        }
        
        // 判断是否正在刷新,如果不是,直接返回
        if refreshView?.refreshState != .WillRefresh {
            return
        }
        
        // 恢复刷新视图的状态
        refreshView?.refreshState = .Normal
        
        // 恢复表格间隔
        sv.contentInset.top -= RefreshOffset
    }
}


// MARK: - 设置界面
extension SSRefreshControl {
    
    fileprivate func setupUI() {
        
        backgroundColor = superview?.backgroundColor
        
        guard let refreshView = refreshView else {
            return
        }
        
        // 添加刷新视图 - 从xib加载出来,默认是xib指定的大小
        addSubview(refreshView)
        
        // 自动布局 - 设置xib控件的自动布局,需要指定约束的宽高
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        
        // 设置位置布局
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0))
        // 设置宽高布局
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: refreshView.bounds.width))
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: refreshView.bounds.height))
    }
}
